<template>
  <RemindDialog
    v-if="dialogVisible"
    v-model="dialogVisible"
    :duration="10000"
    @close="onDialogClose"
  >
    <template #default>
      <div v-if="dialogReminds.length === 1">
        <div class="remind-row remind-single">
          <span class="remind-index">1.</span>
          <span class="remind-time">{{ formatTime(dialogReminds[0].time) }}</span>
          <span class="remind-desc">{{ dialogReminds[0].description }}</span>
        </div>
      </div>
      <div v-else>
        <ul>
          <li v-for="(item, idx) in dialogReminds" :key="item.id" class="remind-row remind-single">
            <span class="remind-index">{{ idx + 1 }}.</span>
            <span class="remind-time">{{ formatTime(item.time) }}</span>
            <span class="remind-desc">{{ item.description }}</span>
          </li>
        </ul>
      </div>
    </template>
  </RemindDialog>
</template>

<script setup>
import { ref, onMounted, onUnmounted, computed, watch } from 'vue';
import RemindDialog from './RemindDialog.vue';
import config from '@/config.js';
import { useUserStore } from '@/store/modules/user.js';
import { ttsPlay, onTtsEvent } from '@/utils/tts.js';

// 构造 WebSocket 地址 (示例：后缀按真实后端调整)
const WS_URL = (config.wsBaseUrl || '').replace(/^http/, 'ws') + '/websocket/remind';

// Pinia 用户信息（动态响应）
const userStore = useUserStore();
const userIdRef = computed(()=> userStore.id || localStorage.getItem('userId') || '0');

// 弹窗 state
const dialogVisible = ref(false);
const dialogReminds = ref([]); // 当前弹窗展示的提醒（可能多条）
// 本次弹窗是否已播报（保证“弹窗出现时播报一次”）
const hasSpokenThisDialog = ref(false);
// 额外防重：对话框级播放时间戳，避免极短时间内重复触发
const lastDialogSpeakAt = ref(0);

// ws 实例
const ws = ref(null);
const lastUserId = ref(null); // 记录已绑定的用户ID
// 已调度 ID 防重复
const scheduledIds = ref(new Set());
// 时间分桶：时间戳(ms) -> { list: Remind[], timer }
const timeBuckets = {};
// 是否立即播报（true: 收到即播；false: 按时间点调度）
const immediateBroadcast = true;

// ===== 去重：最近已播报的提醒 ID 与文本 （可通过 window.__REMIND_CFG 动态调参）=====
const CFG = (typeof window!=='undefined' && window.__REMIND_CFG) ? window.__REMIND_CFG : {};
// alwaysSpeak=true 时：所有去重失效，每次推送都交给 TTS
// 默认 60s，可通过 window.__REMIND_CFG.idTtlMs 调低以便测试或允许重复播报
const SPEAK_ID_TTL = CFG.idTtlMs ?? 60 * 1000;
// 默认 10s 文本去重间隔
const SPEAK_TEXT_TTL = CFG.textTtlMs ?? 10 * 1000;
const recentSpeakIds = new Set();
const recentSpeakTexts = [];// {t,text}
function pruneRecent(){
  const now = Date.now();
  // 由于 Set 不存时间，简单策略：当 size 过大时全量重建（低频）
  if(recentSpeakIds.size > 500){ recentSpeakIds.clear(); }
  for(let i=recentSpeakTexts.length-1;i>=0;i--){ if(now - recentSpeakTexts[i].t > SPEAK_TEXT_TTL) { recentSpeakTexts.splice(i,1); } }
}
function alreadySpoken(id, text){
  if(CFG.alwaysSpeak) return false; // 彻底放开
  pruneRecent();
  if(id && recentSpeakIds.has(id)) return true; // same id within ttl
  if(recentSpeakTexts.some(e=> e.text === text)) return true; // same text within ttl
  return false;
}
function markSpoken(id, text){
  if(id) recentSpeakIds.add(id);
  recentSpeakTexts.push({t:Date.now(), text});
  pruneRecent();
}

// 心跳相关
const HEARTBEAT_INTERVAL = 30000; // 30s 发送一次
const PONG_TIMEOUT = 10000; // 10s 未收到 pong 视为超时
let heartbeatTimer = null;
let pongTimer = null;

function connectWebSocket(){
  // 避免重复连接
  if(ws.value && ws.value.readyState === WebSocket.OPEN) return;
  try { ws.value = new WebSocket(WS_URL); } catch(e){ console.error('WS 创建失败', e); return; }
  const bindUserId = userIdRef.value;
  ws.value.onopen = () => console.log('Remind WS connected for user', bindUserId);
  ws.value.onclose = () => {
    stopHeartbeat();
    // 若组件还在且用户仍是当前ID，尝试重连
    if(bindUserId === userIdRef.value){
      console.log('Remind WS closed, retry in 3s');
      setTimeout(()=>{ if(bindUserId === userIdRef.value) connectWebSocket(); }, 3000);
    }
  };
  ws.value.onerror = (err) => {
    console.error('Remind WS error', err);
    // 添加更详细的错误信息
    if (err.target && err.target.readyState === WebSocket.CLOSED) {
      console.warn('WebSocket连接已关闭，可能原因：');
      console.warn('1. 后端服务未启动');
      console.warn('2. 防火墙阻止连接');
      console.warn('3. nginx代理配置问题');
      console.warn('4. 网络连接问题');
    }
  };
  ws.value.onmessage = (evt) => handleMessage(evt.data);
  startHeartbeat();
}

function closeWebSocket(){
  if(ws.value){ try { ws.value.close(); } catch(_){} }
  ws.value = null;
}

function handleMessage(raw){
  let data; try { data = JSON.parse(raw); } catch(e){ console.warn('提醒消息解析失败', e, raw); return; }
  // 心跳 pong
  if(data && data.type === 'pong'){
    // 收到 pong 说明连接正常
    if(pongTimer){ clearTimeout(pongTimer); pongTimer = null; }
    return;
  }
  if(Array.isArray(data)) return processIncomingList(data);
  if(data && Array.isArray(data.list)) return processIncomingList(data.list);
  if(data && data.userId && data.time && data.description) return processIncomingList([data]);
}

// 处理后台每分钟推送的下一分钟提醒列表
function processIncomingList(list){
  if(!Array.isArray(list)) return;
  const mine = list.filter(r => String(r.userId) === String(userIdRef.value));
  if(!mine.length) return;
  if(immediateBroadcast){
    // 立即播报：同一批次合并（保持原顺序）
    const withIds = mine.map(r => ({ ...r, id: buildId(r) }));
    if(withIds.length === 1) showRemind(withIds[0]); else showMergedRemind(withIds);
  } else {
    // 仍使用时间调度
    mine.forEach(r => scheduleByBucket(r));
  }
}

function scheduleByBucket(remind){
  if(immediateBroadcast){
    // 安全兜底：若外部错误调用仍直接播报
    const withId = { ...remind, id: buildId(remind) };
    showRemind(withId);
    return;
  }
  const id = buildId(remind);
  if(scheduledIds.value.has(id)) return; // 已安排
  scheduledIds.value.add(id);
  const ts = parseTime(remind.time);
  if(!ts){ showRemind(remind); return; }
  if(!timeBuckets[ts]){
    timeBuckets[ts] = { list: [], timer: null };
    const delay = ts - Date.now();
    timeBuckets[ts].timer = setTimeout(()=>{
      const arr = timeBuckets[ts].list; delete timeBuckets[ts];
      if(arr.length === 1) showRemind(arr[0]); else showMergedRemind(arr);
    }, delay > 0 ? delay : 0);
  }
  timeBuckets[ts].list.push({ ...remind, id });
}

function speakBrowser(text){
  if(!text) return;
  if(typeof window === 'undefined' || !('speechSynthesis' in window)){ console.warn('speechSynthesis not supported'); return; }
  try { window.speechSynthesis.cancel(); } catch(_){}
  const utter = new SpeechSynthesisUtterance(text);
  utter.lang = 'zh-CN';
  utter.rate = 1;
  utter.pitch = 1;
  utter.volume = 1;
  try { window.speechSynthesis.speak(utter); } catch(e){ console.warn('speak error', e); }
}
function showRemind(remind){
  const text = buildSpeakText(remind);
  if(alreadySpoken(remind.id, text)) return; // 仍然避免重复展示/播报完全相同的单条
  // 若弹窗未开启，则开启并重置“仅播报一次”标记
  const opening = !dialogVisible.value;
  dialogReminds.value = [remind];
  if(opening){ dialogVisible.value = true; hasSpokenThisDialog.value = false; }
  maybeSpeakForDialog();
  if(!CFG.alwaysSpeak) markSpoken(remind.id, text);
}
function showMergedRemind(reminds){
  if(!reminds || !reminds.length) return;
  let filtered;
  if(CFG.alwaysSpeak){
    filtered = reminds.map(r=> ({...r}));
  } else {
    filtered = reminds.filter(r=> !alreadySpoken(r.id, buildSpeakText(r)));
    if(!filtered.length) return; // 全部播过
  }
  const opening = !dialogVisible.value;
  dialogReminds.value = filtered; // alwaysSpeak 下保留全部
  if(opening){ dialogVisible.value = true; hasSpokenThisDialog.value = false; }
  maybeSpeakForDialog();
  if(!CFG.alwaysSpeak) filtered.forEach(r=> markSpoken(r.id, buildSpeakText(r)));
}

function parseTime(raw){
  if(!raw) return null;
  // 字符串形式：支持 "yyyy-MM-dd HH:mm:ss" 以及 LocalTime 风格 "HH:mm" / "HH:mm:ss"
  if(typeof raw === 'string'){
    const s = raw.trim();
    // LocalTime: HH:mm 或 HH:mm:ss
    if(/^\d{1,2}:\d{2}(:\d{2})?$/.test(s)){
      const [h,m,sec] = s.split(':');
      const now = new Date();
      now.setSeconds(0); now.setMilliseconds(0);
      now.setHours(Number(h)||0, Number(m)||0, sec? Number(sec)||0 : 0, 0);
      const ts = now.getTime();
      return isNaN(ts) ? null : ts;
    }
    // 完整日期时间（或可被 Date 解析的字符串）
    const d = new Date(s.replace(/-/g,'/'));
    const t = d.getTime();
    return isNaN(t) ? null : t;
  }
  // Date 对象
  if(raw instanceof Date) return raw.getTime();
  return null;
}
function buildId(r){
  return `${r.userId || userIdRef.value || 'u'}_${r.time || Date.now()}_${(r.description||'').slice(0,20)}`;
}
function formatTime(timeStr){
  if(!timeStr) return '';
  const m = String(timeStr).match(/(\d{1,2}:\d{2})/);
  return m ? m[1] : timeStr;
}
function buildSpeakText(r){
  const t = formatTime(r.time) || '';
  const d = r.description || '提醒';
  return `【${t? (t + ' '): ''}${d}】`;
}
// 仅用于"弹窗出现时播报一次"的版本：不做批次子集/超集去重，强制播报一次
function speakForDialog(){
  // 如果该弹窗周期内已经播报过，直接返回
  if(hasSpokenThisDialog.value) return;
  const now = Date.now();
  if(now - lastDialogSpeakAt.value < 1500) return; // 减少保护时间到1.5s
  
  // 只设置播放状态，实际播放由playDetailedContent处理
  hasSpokenThisDialog.value = true; // 置为已播报，保证只播报一次
  lastDialogSpeakAt.value = now;
  console.log('[Remind] 播报状态已设置');
}

// 启动一次性播报（仅在弹窗开启那一刻触发）
function maybeSpeakForDialog(){
  if(dialogVisible.value && !hasSpokenThisDialog.value){ 
    console.log('[Remind] 开始播放提醒语音');
    // 立即播放简短提示音，然后异步播放完整内容
    playImmediateNotification();
    speakForDialog();
  }
}

// 立即播放简短提示音
function playImmediateNotification() {
  try {
    if (window.speechSynthesis) {
      // 取消任何正在播放的语音
      window.speechSynthesis.cancel();
      
      // 播放简短的提示音
      const notification = new SpeechSynthesisUtterance('提醒');
      notification.lang = 'zh-CN';
      notification.rate = 1.5;
      notification.pitch = 1.2;
      notification.volume = 0.8;
      
      // 在提示音播放完成后，延迟播放详细内容
      notification.onend = () => {
        console.log('[Remind] 立即提示音播放完成，准备播放详细内容');
        // 延迟一点时间再播放详细内容，避免重叠
        setTimeout(() => {
          if (dialogVisible.value) {
            playDetailedContent();
          }
        }, 200);
      };
      
      // 立即播放，不等待
      window.speechSynthesis.speak(notification);
      
      console.log('[Remind] 立即提示音已播放');
    }
  } catch (error) {
    console.warn('[Remind] 立即提示音播放失败:', error);
  }
}

// 播放详细内容
function playDetailedContent() {
  try {
    const list = dialogReminds.value || [];
    let finalText = '';
    if(list.length === 1){
      finalText = buildSpeakText(list[0]);
    } else if(list.length > 1){
      // 简化多提醒文本，减少播放时间，使用TTS要求的【】格式
      finalText = `【您有${list.length}条提醒：` + list.map((r, i) => `第${i+1}条${r.time}${r.description || '提醒'}`).join('，') + '】';
    }
    if(!finalText) return;
    
    console.log('[Remind] 准备播放详细内容:', finalText);
    ttsPlay(finalText, { operation: 'query', allowRepeat: false })
      .then(() => {
        console.log('[Remind] 详细内容播放成功');
      })
      .catch(err => { 
        console.warn('[Remind] 详细内容播放失败', err); 
      });
  } catch (error) {
    console.warn('[Remind] 播放详细内容失败:', error);
  }
}

// 全局变量跟踪用户交互状态
let userHasInteracted = false;

// 检查是否有用户交互权限
function hasUserInteractionPermission() {
  return userHasInteracted;
}





// 激活音频上下文，解决自动播放被阻止的问题
function activateAudioContext() {
  try {
    // 激活Web Audio API上下文
    if (window.AudioContext || window.webkitAudioContext) {
      const AudioContext = window.AudioContext || window.webkitAudioContext;
      const audioContext = new AudioContext();
      if (audioContext.state === 'suspended') {
        audioContext.resume().then(() => {
          console.log('[Remind] Web Audio API已激活');
        }).catch(error => {
          console.warn('[Remind] Web Audio API激活失败:', error);
        });
      }
    }
  } catch (error) {
    console.warn('[Remind] 音频激活失败:', error);
  }
}

// 保留原有复杂去重 speak 作为备用（目前不再用于弹窗场景）
function speak(_raw){
  const DEBUG = !!(typeof window!=='undefined' && window.__REMIND_DEBUG);
  const dbg = (...a)=>{ if(DEBUG) console.log('[Remind][SpeakDBG]', ...a); };
  let finalText = '';
  const list = dialogReminds.value || [];
  if(CFG.alwaysSpeak){
    if(list.length === 1){
      finalText = buildSpeakText(list[0]);
    } else if(list.length > 1){
      finalText = list.map(r=> buildSpeakText(r)).join('，');
    } else if(_raw){
      finalText = /【.+】/.test(_raw)? _raw : `【${_raw}】`;
    }
  } else {
    // 普通防重逻辑
    if(!window.__recentBatchKeys){ window.__recentBatchKeys = []; }
    const recentBatchKeys = window.__recentBatchKeys; // [{k,ts}]
    const now = Date.now();
    for(let i=recentBatchKeys.length-1;i>=0;i--){ if(now - recentBatchKeys[i].ts > 5000) recentBatchKeys.splice(i,1); }
    if(!window.__recentBatchSets){ window.__recentBatchSets = []; }
    const recentBatchSets = window.__recentBatchSets; // [{parts:Set,ts}]
    const BATCH_SET_WINDOW = CFG.batchSubsetWindowMs ?? 1500;
    for(let i=recentBatchSets.length-1;i>=0;i--){ if(now - recentBatchSets[i].ts > BATCH_SET_WINDOW) recentBatchSets.splice(i,1); }
    const recordAndMaybeSkip = (partsArray)=>{
      const partsSet = new Set(partsArray);
      for(const r of recentBatchSets){
        let isSubset = true; for(const p of partsSet){ if(!r.parts.has(p)){ isSubset=false; break; } }
        let isSuperset = true; for(const p of r.parts){ if(!partsSet.has(p)){ isSuperset=false; break; } }
        if(isSubset || isSuperset) return true;
      }
      recentBatchSets.push({ parts: partsSet, ts: now });
      return false;
    };
    if(list.length === 1){
      finalText = buildSpeakText(list[0]);
      const k = 'single:'+ (list[0].id || finalText);
      if(recentBatchKeys.some(e=> e.k === k)){ dbg('skip same single batch key', k); return; }
      recentBatchKeys.push({k, ts: now});
      if(recordAndMaybeSkip([finalText])){ dbg('skip single subset/superset', finalText); return; }
    } else if(list.length > 1){
      const allIdsSpoken = list.every(r=> alreadySpoken(r.id, buildSpeakText(r)));
      if(allIdsSpoken){ dbg('skip multi all ids already spoken'); return; }
      finalText = list.map(r=> buildSpeakText(r)).join('，');
      const k = 'multi:'+ list.map(r=> r.id || buildSpeakText(r)).sort().join('|');
      if(recentBatchKeys.some(e=> e.k === k)){ dbg('skip same multi batch key', k); return; }
      recentBatchKeys.push({k, ts: now});
      const parts = finalText.match(/【[^】]+】/g) || [finalText];
      if(recordAndMaybeSkip(parts)){ dbg('skip multi subset/superset', parts); return; }
    } else if(_raw){
      finalText = /【.+】/.test(_raw)? _raw : `【${_raw}】`;
      const k = 'raw:'+finalText;
      if(recentBatchKeys.some(e=> e.k === k)){ dbg('skip raw same key', k); return; }
      recentBatchKeys.push({k, ts: now});
      if(recordAndMaybeSkip([finalText])){ dbg('skip raw subset/superset', finalText); return; }
    }
  }
  if(!finalText) return;
  ttsPlay(finalText, { operation: 'query', allowRepeat: CFG.alwaysSpeak })
    .catch(err => { console.warn('[Remind] ttsPlay error (已回退本地朗读)', err); });
}
function onDialogClose(){
  dialogReminds.value = [];
  dialogVisible.value = false;
  hasSpokenThisDialog.value = false;
  if(typeof window !== 'undefined' && 'speechSynthesis' in window){
    try { window.speechSynthesis.cancel(); } catch(_){}
  }
}

// 简单清理过期 bucket，防内存增长
setInterval(()=>{
  const now = Date.now();
  Object.keys(timeBuckets).forEach(k=>{ if(Number(k) + 5*60*1000 < now){ clearTimeout(timeBuckets[k].timer); delete timeBuckets[k]; } });
}, 5*60*1000);

// 清理调度状态（用户切换时使用）
function resetScheduleState(){
  // 清 bucket 计时器
  Object.keys(timeBuckets).forEach(k=>{ try { clearTimeout(timeBuckets[k].timer); } catch(_){} delete timeBuckets[k]; });
  scheduledIds.value = new Set();
  dialogVisible.value = false;
  dialogReminds.value = [];
}

function validUserId(id){ return id && id !== '0'; }

// 监听用户ID变化：首次有效值 -> 连接；后续变化则重置并重连
watch(userIdRef, (newVal, oldVal) => {
  if(!validUserId(newVal)) return; // 等待真正用户ID
  if(newVal === lastUserId.value && ws.value) return; // 无变化
  console.log('[Remind] userId changed', oldVal, '=>', newVal);
  resetScheduleState();
  closeWebSocket();
  lastUserId.value = newVal;
  connectWebSocket();
}, { immediate: true });

let offTts;
onMounted(()=> {
  // 初始化逻辑由 watch 负责
  offTts = onTtsEvent(e=>{
    if(process.env.NODE_ENV!=='production'){
      console.log('[TTS_EVT]', e.type, e);
    }
  });
  
  // 页面加载时预热音频上下文
  warmupAudioContext();
  
  // 添加页面级别的用户交互监听器
  setupUserInteractionListener();
});

// 预热音频上下文，解决自动播放被阻止的问题
function warmupAudioContext() {
  try {
    // 不进行自动尝试，只设置用户交互监听器
    console.log('[Remind] 音频预热完成，等待用户交互');
  } catch (error) {
    console.warn('[Remind] 音频预热失败:', error);
  }
}



// 设置页面级别的用户交互监听器
function setupUserInteractionListener() {
  const handleUserInteraction = () => {
    if (!userHasInteracted) {
      userHasInteracted = true;
      console.log('[Remind] 检测到用户交互，激活音频权限');
      
      // 立即激活音频上下文
      activateAudioContext();
    }
  };
  
  // 监听用户交互事件
  document.addEventListener('click', handleUserInteraction, { once: true });
  document.addEventListener('touchstart', handleUserInteraction, { once: true });
  document.addEventListener('keydown', handleUserInteraction, { once: true });
  
  console.log('[Remind] 用户交互监听器已设置，等待用户交互');
}


onUnmounted(()=> { closeWebSocket(); resetScheduleState(); stopHeartbeat(); if(offTts) offTts(); });

// ---------------- 心跳实现 ----------------
function startHeartbeat(){
  stopHeartbeat();
  heartbeatTimer = setInterval(()=>{
    if(!ws.value || ws.value.readyState !== WebSocket.OPEN) return;
    // 发送 ping
    try { ws.value.send(JSON.stringify({ type: 'ping', t: Date.now() })); } catch(e){ /* ignore */ }
    // 设定 pong 超时
    if(pongTimer) clearTimeout(pongTimer);
    pongTimer = setTimeout(()=>{
      console.warn('心跳超时，准备重连');
      closeWebSocket();
      connectWebSocket();
    }, PONG_TIMEOUT);
  }, HEARTBEAT_INTERVAL);
}
function stopHeartbeat(){
  if(heartbeatTimer){ clearInterval(heartbeatTimer); heartbeatTimer = null; }
  if(pongTimer){ clearTimeout(pongTimer); pongTimer = null; }
}
</script>

<style scoped>
.remind-row { display:flex; align-items:center; gap:10px; font-size:24px; margin-bottom:8px; font-weight:bold; color:#222; }
.remind-single { margin:8px 0; }
.remind-index { font-size:22px; color:#222; font-weight:bold; margin-right:4px; }
.remind-time { color:#222; font-size:24px; font-weight:bold; margin-right:8px; }
.remind-desc { color:#222; font-size:24px; font-weight:bold; letter-spacing:1px; }
</style>